/* do not edit automatically generated by mc from StrLib.  */
/* StrLib.mod provides string manipulation procedures.

Copyright (C) 2001-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include <stdbool.h>
#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#define _StrLib_H
#define _StrLib_C

#   include "GASCII.h"


/*
   StrConCat - combines a and b into c.
*/

extern "C" void StrLib_StrConCat (const char *a_, unsigned int _a_high, const char *b_, unsigned int _b_high, char *c, unsigned int _c_high);

/*
   StrLess - returns TRUE if string, a, alphabetically occurs before
             string, b.
*/

extern "C" bool StrLib_StrLess (const char *a_, unsigned int _a_high, const char *b_, unsigned int _b_high);
extern "C" bool StrLib_StrEqual (const char *a_, unsigned int _a_high, const char *b_, unsigned int _b_high);
extern "C" unsigned int StrLib_StrLen (const char *a_, unsigned int _a_high);

/*
   StrCopy - copy string src into string dest providing dest is large enough.
             If dest is smaller than a then src then the string is truncated when
             dest is full.  Add a nul character if there is room in dest.
*/

extern "C" void StrLib_StrCopy (const char *src_, unsigned int _src_high, char *dest, unsigned int _dest_high);

/*
   IsSubString - returns true if b is a subcomponent of a.
*/

extern "C" bool StrLib_IsSubString (const char *a_, unsigned int _a_high, const char *b_, unsigned int _b_high);

/*
   StrRemoveWhitePrefix - copies string, into string, b, excluding any white
                          space infront of a.
*/

extern "C" void StrLib_StrRemoveWhitePrefix (const char *a_, unsigned int _a_high, char *b, unsigned int _b_high);

/*
   IsWhite - returns TRUE if, ch, is a space or a tab.
*/

static bool IsWhite (char ch);


/*
   IsWhite - returns TRUE if, ch, is a space or a tab.
*/

static bool IsWhite (char ch)
{
  return (ch == ' ') || (ch == ASCII_tab);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   StrConCat - combines a and b into c.
*/

extern "C" void StrLib_StrConCat (const char *a_, unsigned int _a_high, const char *b_, unsigned int _b_high, char *c, unsigned int _c_high)
{
  unsigned int Highb;
  unsigned int Highc;
  unsigned int i;
  unsigned int j;
  char a[_a_high+1];
  char b[_b_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);
  memcpy (b, b_, _b_high+1);

  Highb = StrLib_StrLen ((const char *) b, _b_high);
  Highc = _c_high;
  StrLib_StrCopy ((const char *) a, _a_high, (char *) c, _c_high);
  i = StrLib_StrLen ((const char *) c, _c_high);
  j = 0;
  while ((j < Highb) && (i <= Highc))
    {
      c[i] = b[j];
      i += 1;
      j += 1;
    }
  if (i <= Highc)
    {
      c[i] = ASCII_nul;
    }
}


/*
   StrLess - returns TRUE if string, a, alphabetically occurs before
             string, b.
*/

extern "C" bool StrLib_StrLess (const char *a_, unsigned int _a_high, const char *b_, unsigned int _b_high)
{
  unsigned int Higha;
  unsigned int Highb;
  unsigned int i;
  char a[_a_high+1];
  char b[_b_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);
  memcpy (b, b_, _b_high+1);

  Higha = StrLib_StrLen ((const char *) a, _a_high);
  Highb = StrLib_StrLen ((const char *) b, _b_high);
  i = 0;
  while ((i < Higha) && (i < Highb))
    {
      if (a[i] < b[i])
        {
          return true;
        }
      else if (a[i] > b[i])
        {
          /* avoid dangling else.  */
          return false;
        }
      /* must be equal, move on to next character  */
      i += 1;
    }
  return Higha < Highb;  /* substrings are equal so we go on length  */
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" bool StrLib_StrEqual (const char *a_, unsigned int _a_high, const char *b_, unsigned int _b_high)
{
  unsigned int i;
  unsigned int higha;
  unsigned int highb;
  char a[_a_high+1];
  char b[_b_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);
  memcpy (b, b_, _b_high+1);

  higha = _a_high;
  highb = _b_high;
  i = 0;
  while ((((i <= higha) && (i <= highb)) && (a[i] != ASCII_nul)) && (b[i] != ASCII_nul))
    {
      if (a[i] != b[i])
        {
          return false;
        }
      i += 1;
    }
  return ! (((i <= higha) && (a[i] != ASCII_nul)) || ((i <= highb) && (b[i] != ASCII_nul)));
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" unsigned int StrLib_StrLen (const char *a_, unsigned int _a_high)
{
  unsigned int High;
  unsigned int Len;
  char a[_a_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);

  Len = 0;
  High = _a_high;
  while ((Len <= High) && (a[Len] != ASCII_nul))
    {
      Len += 1;
    }
  return Len;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   StrCopy - copy string src into string dest providing dest is large enough.
             If dest is smaller than a then src then the string is truncated when
             dest is full.  Add a nul character if there is room in dest.
*/

extern "C" void StrLib_StrCopy (const char *src_, unsigned int _src_high, char *dest, unsigned int _dest_high)
{
  unsigned int HighSrc;
  unsigned int HighDest;
  unsigned int n;
  char src[_src_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (src, src_, _src_high+1);

  n = 0;
  HighSrc = StrLib_StrLen ((const char *) src, _src_high);
  HighDest = _dest_high;
  while ((n < HighSrc) && (n <= HighDest))
    {
      dest[n] = src[n];
      n += 1;
    }
  if (n <= HighDest)
    {
      dest[n] = ASCII_nul;
    }
}


/*
   IsSubString - returns true if b is a subcomponent of a.
*/

extern "C" bool StrLib_IsSubString (const char *a_, unsigned int _a_high, const char *b_, unsigned int _b_high)
{
  unsigned int i;
  unsigned int j;
  unsigned int LengthA;
  unsigned int LengthB;
  char a[_a_high+1];
  char b[_b_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);
  memcpy (b, b_, _b_high+1);

  LengthA = StrLib_StrLen ((const char *) a, _a_high);
  LengthB = StrLib_StrLen ((const char *) b, _b_high);
  i = 0;
  if (LengthA > LengthB)
    {
      while (i <= (LengthA-LengthB))
        {
          j = 0;
          while ((j < LengthB) && (a[i+j] == b[j]))
            {
              j += 1;
            }
          if (j == LengthB)
            {
              return true;
            }
          else
            {
              i += 1;
            }
        }
    }
  return false;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   StrRemoveWhitePrefix - copies string, into string, b, excluding any white
                          space infront of a.
*/

extern "C" void StrLib_StrRemoveWhitePrefix (const char *a_, unsigned int _a_high, char *b, unsigned int _b_high)
{
  unsigned int i;
  unsigned int j;
  unsigned int higha;
  unsigned int highb;
  char a[_a_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);

  i = 0;
  j = 0;
  higha = StrLib_StrLen ((const char *) a, _a_high);
  highb = _b_high;
  while ((i < higha) && (IsWhite (a[i])))
    {
      i += 1;
    }
  while ((i < higha) && (j <= highb))
    {
      b[j] = a[i];
      i += 1;
      j += 1;
    }
  if (j <= highb)
    {
      b[j] = ASCII_nul;
    }
}

extern "C" void _M2_StrLib_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}

extern "C" void _M2_StrLib_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}
